package com.dng.book.service.impl;

import cn.hutool.core.util.StrUtil;
import com.dng.book.service.TokenService;
import com.dng.book.util.RedisUtil;
import com.dng.book.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * Token服务实现类
 *
 * @author dng
 * @since 2024-01-01
 */
@Slf4j
@Service
public class TokenServiceImpl implements TokenService {

    @Resource
    private RedisUtil redisUtil;

    private static final String TOKEN_KEY_PREFIX = "token:";
    private static final String USER_TOKEN_KEY_PREFIX = "user_token:";
    private static final long TOKEN_EXPIRE_TIME = 24 * 60 * 60; // 24小时

    @Override
    public String generateAndStoreToken(String username) {
        if (StrUtil.isBlank(username)) {
            throw new IllegalArgumentException("用户名不能为空");
        }

        // 生成Token
        String token = TokenUtil.generateToken(username);
        
        // 存储到Redis，设置过期时间
        String tokenKey = TOKEN_KEY_PREFIX + token;
        String userTokenKey = USER_TOKEN_KEY_PREFIX + username;
        
        // 删除旧的Token（如果存在）
        String oldToken = redisUtil.get(userTokenKey);
        if (StrUtil.isNotBlank(oldToken)) {
            redisUtil.delete(TOKEN_KEY_PREFIX + oldToken);
            log.info("删除旧Token - 用户名: {}, 旧Token: {}", username, oldToken);
        }
        
        // 存储新Token
        redisUtil.set(tokenKey, username, TOKEN_EXPIRE_TIME, TimeUnit.SECONDS);
        redisUtil.set(userTokenKey, token, TOKEN_EXPIRE_TIME, TimeUnit.SECONDS);
        
        log.info("Token存储成功 - 用户名: {}, Token: {}, 过期时间: {}秒", username, token, TOKEN_EXPIRE_TIME);
        
        return token;
    }

    @Override
    public String validateToken(String token) {
        if (StrUtil.isBlank(token)) {
            log.warn("Token为空");
            return null;
        }

        // 验证Token格式
        if (!TokenUtil.isValidTokenFormat(token)) {
            log.warn("Token格式无效: {}", token);
            return null;
        }

        // 从Redis中获取Token对应的用户名
        String tokenKey = TOKEN_KEY_PREFIX + token;
        String username = redisUtil.get(tokenKey);
        
        if (StrUtil.isBlank(username)) {
            log.warn("Token不存在或已过期: {}", token);
            return null;
        }

        // 验证Token中的用户名与Redis中存储的用户名是否一致
        String tokenUsername = TokenUtil.extractUsername(token);
        if (!username.equals(tokenUsername)) {
            log.warn("Token用户名不匹配 - Token中: {}, Redis中: {}", tokenUsername, username);
            return null;
        }

        log.info("Token验证成功 - 用户名: {}, Token: {}", username, token);
        return username;
    }

    @Override
    public void removeToken(String token) {
        if (StrUtil.isBlank(token)) {
            return;
        }

        String tokenKey = TOKEN_KEY_PREFIX + token;
        String username = redisUtil.get(tokenKey);
        
        if (StrUtil.isNotBlank(username)) {
            String userTokenKey = USER_TOKEN_KEY_PREFIX + username;
            redisUtil.delete(tokenKey);
            redisUtil.delete(userTokenKey);
            log.info("Token删除成功 - 用户名: {}, Token: {}", username, token);
        }
    }

    @Override
    public boolean refreshToken(String token) {
        if (StrUtil.isBlank(token)) {
            return false;
        }

        String tokenKey = TOKEN_KEY_PREFIX + token;
        String username = redisUtil.get(tokenKey);
        
        if (StrUtil.isBlank(username)) {
            return false;
        }

        // 刷新Token过期时间
        String userTokenKey = USER_TOKEN_KEY_PREFIX + username;
        Boolean tokenResult = redisUtil.expire(tokenKey, TOKEN_EXPIRE_TIME, TimeUnit.SECONDS);
        Boolean userTokenResult = redisUtil.expire(userTokenKey, TOKEN_EXPIRE_TIME, TimeUnit.SECONDS);
        
        boolean success = Boolean.TRUE.equals(tokenResult) && Boolean.TRUE.equals(userTokenResult);
        
        if (success) {
            log.info("Token刷新成功 - 用户名: {}, Token: {}", username, token);
        } else {
            log.warn("Token刷新失败 - 用户名: {}, Token: {}", username, token);
        }
        
        return success;
    }
} 